﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;

namespace FreeFlow.Administration
{
  /// <summary>
  /// A collection of versions of a published WF.
  /// </summary>
  public sealed class WorkflowVersionCollection : DatabaseAware, IEnumerable<WorkflowVersion>, IList
  {
    private Workflow workflow;
    /// <summary>
    /// Initializes a new instance of the <see cref="WorkflowVersionCollection"/> class.
    /// </summary>
    /// <param name="server">The server.</param>
    /// <param name="workflow">The workflow.</param>
    public WorkflowVersionCollection(Server server, Workflow workflow) : base(server)
    {
      this.workflow = workflow;
    }

    #region IEnumerable<WorkflowVersion> Members

    /// <summary>
    /// Returns an enumerator that iterates through the collection.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
    /// </returns>
    public IEnumerator<WorkflowVersion> GetEnumerator()
    {
      ReadVersions();
      return versions.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
      ReadVersions();
      return versions.GetEnumerator();
    }

    #endregion

    private List<WorkflowVersion> versions;
    /// <summary>
    /// Gets the number of versions of thie workflow.
    /// </summary>
    /// <value>The count.</value>
    public int Count
    {
      get
      {
        ReadVersions();
        return versions.Count;
      }
    }

    private void ReadVersions()
    {
      if (versions == null)
      {
        versions = new List<WorkflowVersion>();
        using (IDataReader reader = Server.ExecuteReader(string.Format(
          "SELECT * FROM eMSWorkflowDefinition WHERE eWorkflowName='{0}' ORDER BY eLoadedTime DESC", SqlEscape(workflow.Name))))
        {
          while (reader.Read())
          {
            WorkflowVersion wf = new WorkflowVersion(Server, reader);
            versions.Add(wf);
          }
        }
      }
    }

    #region IList Members

    int IList.Add(object value)
    {
      throw new NotSupportedException(readOnlyListMessage);
    }

    void IList.Clear()
    {
      throw new NotSupportedException(readOnlyListMessage);
    }

    /// <summary>
    /// Determines whether the <see cref="T:System.Collections.IList"/> contains a specific value.
    /// </summary>
    /// <param name="value">The <see cref="T:System.Object"/> to locate in the <see cref="T:System.Collections.IList"/>.</param>
    /// <returns>
    /// true if the <see cref="T:System.Object"/> is found in the <see cref="T:System.Collections.IList"/>; otherwise, false.
    /// </returns>
    public bool Contains(object value)
    {
      ReadVersions();
      return versions.Contains((WorkflowVersion)value);
    }

    /// <summary>
    /// Determines the index of a specific item in the <see cref="T:System.Collections.IList"/>.
    /// </summary>
    /// <param name="value">The <see cref="T:System.Object"/> to locate in the <see cref="T:System.Collections.IList"/>.</param>
    /// <returns>
    /// The index of <paramref name="value"/> if found in the list; otherwise, -1.
    /// </returns>
    public int IndexOf(object value)
    {
      ReadVersions();
      return versions.IndexOf((WorkflowVersion)value);
    }

    void IList.Insert(int index, object value)
    {
      throw new NotSupportedException(readOnlyListMessage);
    }

    /// <summary>
    /// Gets a value indicating whether the <see cref="T:System.Collections.IList"/> has a fixed size.
    /// </summary>
    /// <value></value>
    /// <returns>true if the <see cref="T:System.Collections.IList"/> has a fixed size; otherwise, false.</returns>
    public bool IsFixedSize
    {
      get 
      {
        return true;
      }
    }

    /// <summary>
    /// Gets a value indicating whether the <see cref="T:System.Collections.IList"/> is read-only.
    /// </summary>
    /// <value></value>
    /// <returns>true if the <see cref="T:System.Collections.IList"/> is read-only; otherwise, false.</returns>
    public bool IsReadOnly
    {
      get
      {
        return true;
      }
    }

    /// <summary>
    /// Removes the specified version of workflow from the collection and the database.
    /// </summary>
    /// <param name="version">The version of the workflow to remove.</param>
    public void Remove(WorkflowVersion version)
    {
      ReadVersions();
      if (versions.Contains(version))
      {
        version.Delete();
        versions.Remove(version);
      }
    }

    void IList.Remove(object value)
    {
      Remove((WorkflowVersion)value);
    }

    void IList.RemoveAt(int index)
    {
      throw new NotSupportedException(readOnlyListMessage);
    }

    /// <summary>
    /// Gets the <see cref="System.Object"/> at the specified index.
    /// </summary>
    /// <value></value>
    public object this[int index]
    {
      get
      {
        ReadVersions();
        return versions[index];
      }
      set
      {
        throw new NotSupportedException(readOnlyListMessage);
      }
    }

    #endregion

    #region ICollection Members

    /// <summary>
    /// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
    /// </summary>
    /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param>
    /// <param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param>
    /// <exception cref="T:System.ArgumentNullException">
    /// 	<paramref name="array"/> is null. </exception>
    /// <exception cref="T:System.ArgumentOutOfRangeException">
    /// 	<paramref name="index"/> is less than zero. </exception>
    /// <exception cref="T:System.ArgumentException">
    /// 	<paramref name="array"/> is multidimensional.-or- <paramref name="index"/> is equal to or greater than the length of <paramref name="array"/>.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>. </exception>
    /// <exception cref="T:System.ArgumentException">The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>. </exception>
    public void CopyTo(WorkflowVersion[] array, int index)
    {
      ReadVersions();
      versions.CopyTo(array, index);
    }

    void ICollection.CopyTo(Array array, int index)
    {
      CopyTo((WorkflowVersion[])array, index);
    }

    /// <summary>
    /// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread safe).
    /// </summary>
    /// <value></value>
    /// <returns>true if access to the <see cref="T:System.Collections.ICollection"/> is synchronized (thread safe); otherwise, false.</returns>
    public bool IsSynchronized
    {
      get 
      {
        return false;
      }
    }

    /// <summary>
    /// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.
    /// </summary>
    /// <value></value>
    /// <returns>An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"/>.</returns>
    public object SyncRoot
    {
      get 
      { 
        return null; 
      }
    }

    #endregion
  }
}
